﻿using System;
using System.ServiceModel;
using System.Threading;
using CommonUtils;
using Ensemble;

namespace SearchFrontEnd
{
    using BackEndServerList = ServerList<SearchBackendClient, ISearchBackend>;
    using FrontEndMessage = ServerMessage<MessageType>;
    /// <summary>
    /// Implementation of the interface between the front end server and the
    /// back end servers.
    /// </summary>
    public class SearchRegistry : ISearchRegistry
    {
        /// <summary>
        /// Registers a BE server in the registry of the front end server.
        /// When a BE registers at some FE server, the FE will spread the
        /// information to all his group members.
        /// </summary>
        /// <param name="address">Back end server's address.</param>
        public void AddBackEndServer(Uri address) 
        {
            Print.DebugEmit("AddBackEndServer: " + address);
            EndpointAddress endpointAddr = new EndpointAddress(address.AbsoluteUri);
            BackEndServerList.AddServer(
                                   "NetTcpBinding_ISearchBackend",
                                   endpointAddr
                                   );

            //
            // Notify all of the other servers in the group about the BE
            // server that registered with this server.
            //

            // Create the message to multicast
            FrontEndMessage msg = new FrontEndMessage(
                MessageType.AddBackEndSrv,
                endpointAddr.ToString()
                );

            byte[] msgBytes = msg.Serialize();
            if (msgBytes == null)
            {
                // we should never get here.
                Console.WriteLine(
                        "An error occurred while attempting to register the BE server {0}.",
                        address
                        );
                throw new Exception("Message serialization failed.");
            }

            // Send the created message to everyone.
            lock (FEGroupCommunication.Conn)
            {
                while (true)
                {
                    Member.Status status = FEGroupCommunication.Memb.current_status;
                    if (status == Member.Status.Normal)
                    {
                       FEGroupCommunication.Memb.Cast(msgBytes);
                       break; 
                    }
                    if (status == Member.Status.Blocked) 
                    {
                        // currently blocked - wait until the new view is 
                        // installed and try again
                        Thread.Sleep(100);
                    }
                    else 
                    {
                        /* The other possible states are: Pre, Joining, 
                         * Leaving and Left.
                         * We can't be at any of these states at this stage,                   
                         * according to the assumption that:
                         *      "Each back end server is given an URI of some 
                         *       front end server. 
                         *       This front end server is up and running at the 
                         *       time of back end server initialization."
                         *  So, we do nothing.*/
                        continue;
                    }
                }
            }
        }

        /// <summary>
        /// Removes registration of a back end server in the registry of the 
        /// front end server.
        /// </summary>
        /// <param name="address">Back end server's address.</param>
        public void RemoveBackEndServer(Uri address)
        {
            Print.DebugEmit("RemoveBackEndServer: " + address);
            EndpointAddress endpointAddr = new EndpointAddress(address.AbsoluteUri);
            BackEndServerList.RemoveServer(endpointAddr);
            FEGroupCommunication.NotifyBackEndServerIsDown(endpointAddr);
        }
    }
}
